今天的設計模式,讓我們來了解屬於結構型模式的 Facade,中文翻為門面模式、表象模式或外觀模式。Facade 這個詞源自法文 Façade,意思是建築物的正面。
顧名思義,門面模式是為了讓我們有一個簡潔俐落的門面(介面)而存在,把建築物裡面複雜的構成跟各種細碎的細節隱藏起來,留下對外互動的一致窗口。它的目的是用一個高層介面包裝各個子系統,由這個統一對外介面與客戶端進行溝通。例如為一個 library、frameworrk 或任何其他複雜的物件組成提供一個簡化的介面。
門面模式就像客服專員,是你可以接觸到這家公司所有服務的窗口。透過一個電話的語音介面,你就可以知道商品存貨、物流配送、處理退換貨等等。你不必親自去接洽每個不同功能的部門,也不用了解他們內部每天運作的細節,只要透過客服專員幫你快速解決眼前的問題就好。
圖片引用自 Refactoring Guru
請大家先一起回到 Apple TV 出現讓一切變得太簡單前(著實不久之前)的時代。今天我們打造了一個夢想中的超級家庭劇院(甚至有爆米花機)。為了和朋友們一起觀看期待已久、特地租來的電影 DVD,我們還要跨越最後一道關卡,就是所有影音裝置的軟硬體設置!以下是我們需要執行的任務:
使用 Swift,寫成程式碼便會如下所示,我們發現只是想單純的看個電影,就必須用到六個不同的類別。
popper.on()
popper.pop()
lights.dim()
screen.down()
projector.on()
projector.setInput(to: dvdPlayer)
amplifier.on()
amplifier.setTo(dvdPlayer)
amplifier.setSurroundSound()
amplifier.setVolume(5)
dvdPlayer.on()
dvdPlyer.play(movie)
不只是這樣,當我們看完電影,該怎麼把所有設備關掉?要重新依序做一遍相反的程序嗎?如果今天我們要用同一套設備聽 CD,會是用一樣複雜的方式做設定嗎?如果有一天你決定要升級某些硬體,該怎麼調整這個流程?
現在我們可以明顯感受到這個家庭劇院的系統複雜性了,就讓門面模式來解決這個問題,好讓我們能夠好好看場電影,不為這些開開關關、連不連線的瑣事心煩!
門面模式讓我們有了一個厲害的遙控器,讓我們只需要按一個按鈕,就可以透過遙控器上的捷徑快速達成目的。首先我們來建構這個寫作門面,讀作遙控器的類別,讓它取得房間內所有硬體裝置的控制權限。
class HomeTheaterFacade {
let amplifier: Amplifier
let dvdPlayer: DvdPlayer
let cdPlayer: CdPlayer
let projector: Projector
let lights: TheaterLights
let screen: Screen
let popper: PopcornPopper
init(amplifier: Amplifier,
dvdPlayer: DvdPlayer,
cdPlayer: CdPlayer,
projector: Projector,
lights: TheaterLights,
screen: Screen,
popper: PopcornPopper) {
self.amplifier = amplifier
self.dvdPlayer = dvdPlayer
self.cdPlayer = cdPlayer
self.projector = projector
self.lights = lights
self.screen = screen
self.popper = popper
}
// Facade 要實作的方法
}
接著就來實作這個簡化的介面,將子系統的元件組合成統一的介面。以下我們實作 HomeTheaterFacade
的 watchMovie()
和 endMovie()
兩個方法:
func watchMovie(movie: String) {
print("--準備看電影--")
popper.on()
popper.pop()
lights.dim()
screen.down()
projector.on()
amplifier.on()
amplifier.setTo(dvdPlayer)
amplifier.setSurroundSound()
amplifier.setVolume(5)
dvdPlayer.on()
dvdPlayer.play(movie)
}
func endMovie() {
print("--關閉家庭劇院--")
popper.off()
lights.on()
screen.up()
projector.off()
amplifier.off()
dvdPlayer.stop()
dvdPlayer.eject()
dvdPlayer.off()
}
現在有了遙控器,用超級家庭劇院看電影變得非常簡單了!只需要呼叫 homeTheaterFacade.watchMovie()
就能開心看電影了,看完電影後關閉各個設備也能一鍵解決;同理,要用家庭劇院聽 CD 當然也不是問題。
homeTheaterFacade.watchMovie("名偵探柯南:貝克街的亡靈")
homeTheaterFacade.endMovie()
homeTheaterFacade.playCd("歡唱童謠")
優點是能讓你的程式與複雜的子系統隔離開來。缺點是 Facade 這個物件可能會變成跟客戶端所有類別都耦合的 God Object(Anti-Pattern,一個了解過多或者負責過多的物件)。
以上是今天的門面模式,謝謝你的閱覽,我們明天再見!
作者:Jo